﻿using System.Diagnostics.CodeAnalysis;
using System.Net.Http.Headers;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json.Serialization;
using ApiLib.Utils;

namespace ApiLib.Helpers;

/// <summary>
/// 短信
/// </summary>
[SuppressMessage("ReSharper", "StringLiteralTypo")]
public static class SmsHelper
{
    /// <summary>
    /// 中国移动云MAS短信
    /// </summary>
    public class ChinaMobileMas
    {
        private const string TwoHttpUrl = "http://112.35.1.155:1992";//二平台
        private const string TwoHttpsUrl = "https://112.35.10.201:28888";
        private const string NineHttpUrl = "http://112.33.46.17:37891";//九平台
        private const string NineHttpsUrl = "https://112.33.46.17:37892";//九平台

        /// <summary>
        /// 发送模板短信
        /// </summary>
        /// <param name="body"></param>
        /// <param name="secretKey"></param>
        /// <param name="isHttps"></param>
        /// <returns></returns>
        public static bool SendTemplateSms(SmsTemplateBody body, string secretKey, bool isHttps = true,ChinaMobileMasPlatform platform=ChinaMobileMasPlatform.Two)
        {
            var startTime = DateTime.Now;
            try
            {
                body.BuildMac(secretKey);
                var encode = EncryptUtil.Base64Util.Base64Encode(body.Serialize());
                WebUtil.LogInfo("云MAS短信发送："+encode);
                var host = platform switch
                {
                    ChinaMobileMasPlatform.Two => isHttps ? TwoHttpsUrl : TwoHttpUrl,
                    ChinaMobileMasPlatform.Nine => isHttps ? NineHttpsUrl : NineHttpUrl,
                    _ => throw new ArgumentOutOfRangeException(nameof(platform), platform, null)
                };
                var responseBody = HttpUtil.HttpPost<SmsResponseBody>($"{host}/sms/tmpsubmit", null, encode,
                    HttpContentType.Text);
                return responseBody is { Success: true };
            }
            catch (Exception e)
            {
                LogError(e.Message);
                return false;
            }
            finally
            {
                LogInformation("发送短信耗时 " + (DateTime.Now - startTime).TotalMilliseconds);
            }
        }

        /// <summary>
        /// 短信发送返回内容
        /// </summary>
        public class SmsResponseBody
        {
            /// <summary>
            /// 响应状态
            /// IllegalMac	mac校验不通过。
            /// IllegalSignId	无效的签名编码。
            /// InvalidMessage	非法消息，请求数据解析失败。
            /// InvalidUsrOrPwd	非法用户名/密码。
            /// NoSignId	未匹配到对应的签名信息。
            /// success	数据验证通过。
            /// TooManyMobiles	手机号数量超限（&gt;5000），应≤5000。
            /// </summary>
            [JsonPropertyName("rspcod")]
            public string Codo { get; set; }

            /// <summary>
            /// 消息批次号，由云MAS平台生成，用于关联短信发送请求与状态报告，注：若数据验证不通过，该参数值为空。
            /// </summary>
            [JsonPropertyName("mgsGroup")]
            public string MsgNo { get; set; }

            /// <summary>
            /// 数据校验结果
            /// </summary>
            [JsonPropertyName("success")]
            public bool Success { get; set; }
        }

        /// <summary>
        /// 模版短息请求体
        /// </summary>
        public class SmsTemplateBody
        {
            /// <summary>
            /// 企业名称
            /// </summary>
            [JsonPropertyName("ecName")]
            public string EcName { get; set; }

            /// <summary>
            /// 接口账号用户名
            /// </summary>
            [JsonPropertyName("apId")]
            public string ApId { get; set; }

            /// <summary>
            /// 模版ID
            /// </summary>
            [JsonPropertyName("templateId")]
            public string TemplateId { get; set; }

            /// <summary>
            /// 收信手机号码,英文逗号分隔
            /// </summary>
            [JsonPropertyName("mobiles")]
            public string Mobiles { get; set; }

            /// <summary>
            /// 短信参数[\"123456\",\"hello\"]
            /// </summary>
            [JsonPropertyName("params")]
            public string Params { get; set; }

            /// <summary>
            /// 签名编码。在云MAS平台『管理』→『接口管理』→『短信接入用户管理』获取。
            /// </summary>
            [JsonPropertyName("sign")]
            public string Sign { get; set; }

            /// <summary>
            /// 扩展码。依据申请开户的服务代码匹配类型而定，如为精确匹配，此项填写空字符串（""）；如为模糊匹配，此项可填写空字符串或自定义的扩展码，注：服务代码加扩展码总长度不能超过20位。
            /// </summary>
            [JsonPropertyName("addSerial")]
            public string AddSerial { get; set; }

            /// <summary>
            /// 参数校验序列，生成方法：将ecName、apId、secretKey、mobiles、content、sign、addSerial按序拼接（无间隔符），通过MD5（32位小写）计算得出值。
            /// </summary>
            [JsonPropertyName("mac")]
            public string Mac { get; set; }

            /// <summary>
            /// 创建mac
            /// </summary>
            /// <param name="secretKey"></param>
            public void BuildMac(string secretKey)
            {
                var macStr = EcName + ApId + secretKey + TemplateId + Mobiles + Params + Sign + AddSerial;
                Mac = EncryptUtil.HashUtil.Md5(macStr).ToLower();
            }
        }
        /// <summary>
        /// 短信平台
        /// </summary>
        public enum ChinaMobileMasPlatform{
            /// <summary>
            /// 二平台
            /// </summary>
            Two,
            /// <summary>
            /// 九平台
            /// </summary>
            Nine
        }
    }

    /// <summary>
    /// 七牛云短信
    /// </summary>
    public class QiniuSms
    {
        /// <summary>
        /// appid
        /// </summary>
        private string _accesskey = "";

        /// <summary>
        /// 秘钥
        /// </summary>
        private string _secretkey = "";

        /// <summary>
        /// 
        /// </summary>
        private const string Url = "https://sms.qiniuapi.com/v1/message";

        private QiniuSms()
        {
        }

        /// <summary>
        /// 获取实例
        /// </summary>
        /// <param name="ak"></param>
        /// <param name="sk"></param>
        /// <returns></returns>
        public static QiniuSms GetInstance(string ak, string sk)
        {
            return new QiniuSms() { _accesskey = ak, _secretkey = sk };
        }

        /// <summary>
        /// 获取验证码
        /// </summary>
        /// <param name="body"></param>
        /// <returns></returns>
        public bool SendTemplateSms(SmsTemplateBody body)
        {
            var startTime = DateTime.Now;
            try
            {
                // ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
                // {"mobiles":["13458191634"],"template_id":"1351413500156592128","parameters":{"code":"123456"}}
                var postData = body.Serialize();
                var authorization = GetAuthorization(postData);
                var header = new Dictionary<string, string> { { "Authorization", authorization } };
                var content = PostResponse(Url, header, postData);
                LogInformation(content);
                var responseBody = content.Deserialize<Dictionary<string, string>>();
                return responseBody != null && responseBody.ContainsKey("job_id");
            }
            catch (Exception e)
            {
                LogError(e.Message);
                return false;
            }
            finally
            {
                LogInformation("发送短信耗时 " + (DateTime.Now - startTime).TotalMilliseconds);
            }
        }

        private string GetAuthorization(string json)
        {
            var content = new StringBuilder("POST /v1/message\n");
            content.Append("Host: sms.qiniuapi.com\n");
            content.Append("Content-Type: application/json\n\n");
            content.Append(json);
            // + -> -  / -> _  安全的base64
            var replace = Convert.ToBase64String(HashHmac(content.ToString(), _secretkey))
                .Replace('+', '-').Replace('/', '_');
            return "Qiniu " + _accesskey + ":" + replace;
        }

        private static byte[] HashHmac(string signatureString, string secretKey)
        {
            var enc = Encoding.UTF8;
            var hmac = new HMACSHA1(enc.GetBytes(secretKey));
            hmac.Initialize();
            var buffer = enc.GetBytes(signatureString);
            return hmac.ComputeHash(buffer);
        }

        /// <summary>
        /// post请求
        /// </summary>
        /// <param name="url"></param>
        /// <param name="headers"></param>
        /// <param name="postData">post数据</param>
        /// <returns></returns>
        private static string PostResponse(string url, Dictionary<string, string> headers, string postData)
        {
            HttpContent httpContent = new StringContent(postData);
            httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
            var httpClient = new HttpClient();
            if (headers is { Count: > 0 })
            {
                foreach (var item in headers)
                {
                    httpClient.DefaultRequestHeaders.Add(item.Key, item.Value);
                }
            }

            var response = httpClient.PostAsync(url, httpContent).Result;
            return response.IsSuccessStatusCode ? response.Content.ReadAsStringAsync().Result : string.Empty;
        }

        /// <summary>
        /// 模版短信内容<br/>
        /// </summary>
        public class SmsTemplateBody
        {
            /// <summary>
            /// 号码
            /// </summary>
            [JsonPropertyName("mobiles")]
            public string[] Mobiles { get; set; }

            /// <summary>
            /// 模板ID
            /// </summary>
            [JsonPropertyName("template_id")]
            public string Template { get; set; }

            /// <summary>
            /// 参数
            /// </summary>
            [JsonPropertyName("parameters")]
            public Dictionary<string, string> Params { get; set; }
        }
    }


    private static void LogInformation(string msg)
    {
        WebUtil.LogInfo(msg);
    }

    private static void LogError(string msg)
    {
        WebUtil.Error(msg);
    }
}